package service

import (
	"errors"
	"fmt"
	"strings"
	"sync"

	"github.com/jinzhu/copier"
)

// ErrAlreadyExists error return
var ErrAlreadyExists = errors.New("记录已经存在")
var ErrNotFound = errors.New("记录不存在")

// Filter 查询条件
type Filter struct {
	MaxPrice float32 // 最大价格
	NameLike string  // 名称包含
}

// ProductStore 产品仓库接口
type ProductStore interface {
	Save(product *Product) error
	FindByID(id string) (*Product, error)
	FindByBarcode(barcode string) (*Product, error)
	Search(filter *Filter) ([]*Product, error)
}

// Product 产品
type Product struct {
	ID      string  `json:"id"`      // 产品ID
	Name    string  `json:"name"`    // 产品名称
	BarCode string  `json:"barcode"` // 产品国条码
	Price   float32 `json:"price"`   // 产品价格
	Desc    string  `json:"desc"`    // 产品描述
}

// InMemoryProductStore 使用内存进行存储
type InMemoryProductStore struct {
	mutex    sync.RWMutex
	products map[string]*Product
}

// NewProduct 返回一个产品信息
func NewInMemoryProductStore() *InMemoryProductStore {
	return &InMemoryProductStore{
		products: make(map[string]*Product),
	}
}

// Save 把产品存储到仓库
func (store *InMemoryProductStore) Save(product *Product) error {
	store.mutex.Lock()
	defer store.mutex.Unlock()
	if store.products[product.ID] != nil {
		return ErrAlreadyExists
	}

	other, err := deepCopy(product)
	if err != nil {
		return err
	}
	store.products[other.ID] = other
	return nil
}

// Find 根据产品ID，在仓库中查找产品
func (store *InMemoryProductStore) FindByID(id string) (*Product, error) {
	store.mutex.RLock()
	defer store.mutex.RUnlock()
	product := store.products[id]
	if product == nil {
		return nil, ErrNotFound
	}
	// deep copy
	return deepCopy(product)

}

// Find 根据国标码，在仓库中查找产品
func (store *InMemoryProductStore) FindByBarcode(barcode string) (*Product, error) {
	store.mutex.RLock()
	defer store.mutex.RUnlock()
	for _, product := range store.products {
		if product.BarCode == barcode {
			other, err := deepCopy(product)
			if err != nil {
				return nil, err
			}
			return other, nil
		}
	}
	return nil, ErrNotFound
}

// Search 在仓库中搜索搜索产品
func (store *InMemoryProductStore) Search(filter *Filter) ([]*Product, error) {
	store.mutex.RLock()
	defer store.mutex.RUnlock()
	products := make([]*Product, 1) // 默认能找到一个，这个可以根据情况调整
	for _, product := range store.products {
		if isQualified(filter, product) {
			other, err := deepCopy(product)
			if err != nil {
				return nil, err
			}
			products = append(products, other)
		}
	}
	return products, nil
}

// deepCopy 再复制一份出来，防止修改原始数据
func deepCopy(product *Product) (*Product, error) {
	other := &Product{}
	err := copier.Copy(other, product)
	if err != nil {
		return nil, fmt.Errorf("复制数据时发生错误: %w", err)
	}

	return other, nil
}

func isQualified(filter *Filter, product *Product) bool {
	if product.Price > filter.MaxPrice {
		return false
	}
	// 判断产品名称中是否包含搜索字
	if !strings.Contains(product.Name, filter.NameLike) {
		return false
	}

	return true

}
